import { AbstractModel } from '@/model/model'
import type { Position } from '@/service/position'
import { imageMap, type ImageType } from '@/service/image'
import config from '@/config'
import water from '@/canvas/water'
import wall from '@/canvas/wall'
import steel from '@/canvas/steel'
import _ from 'lodash'

export type Direct = keyof typeof config.tank.directs

class Tank extends AbstractModel {
    public direct: Direct = 'top' // 坦克的方向

    public constructor(ctx: CanvasRenderingContext2D, position: Position) {
        super(ctx, position)
        this.randomDirect()
    }

    public move() {
        const step = config.tank.step
        while (true) {
            let x = this.x
            let y = this.y

            // 坦克随机掉头
            const r = _.random(0, 1500)
            if (r >= 600 && r <= 630) {
                this.randomDirect()
            }

            switch (this.direct) {
                case 'top':
                    y -= step
                    break
                case 'bottom':
                    y += step
                    break
                case 'left':
                    x -= step
                    break
                case 'right':
                    x += step
                    break
            }
            if (this.isTouch(x, y)) {
                this.randomDirect()
            } else {
                this.x = x
                this.y = y
                break
            }
        }
    }

    protected isTouch(x: number, y: number) {
        const touchEdge = x < 0 || x + this.width > config.canvas.width || y < 0 || y + this.height > config.canvas.height
        if (touchEdge) {
            return true
        }
        const models: AbstractModel[] = [...water.models, ...wall.models, ...steel.models]

        // 只要有一个撞上了就返回 true
        const touchBarrier = models.some((model) => {
            // 没撞上
            const state = x + this.width <= model.x || x >= model.x + model.width || y + this.height <= model.y || y >= model.y + model.height
            // 撞上了
            return !state
        })
        return touchBarrier
    }

    /**
     * 根据权重获得坦克的随机方向。初始化 direct 属性
     */
    protected randomDirect() {
        let weightSum = 0
        const orientations = Object.keys(config.tank.directs)
        const weights = Object.entries(config.tank.directs).map(([_, v]) => v.weight)
        const random = Math.floor(_.random(0, 1, true) * weights.reduce((pre, cur) => pre + cur, 0))
        // 轮盘赌法： [[0, 2], [2, 4], [4, 6], [6, 10]].findIndex(([x, y]) => x <= random && random < y)
        let i = weights.map((d) => [weightSum, (weightSum += d)]).findIndex(([x, y]) => x <= random && random < y)
        this.direct = orientations[i] as Direct
    }

    protected override getImage(): HTMLImageElement {
        return imageMap.get(`tank-${this.direct}` as ImageType)!
    }
}

export default Tank
